 ///
 /// @file    Complex.cc
 /// @author  lemon(haohb13@gmail.com)
 /// @date    2023-04-27 10:04:17
 ///
 
#include <limits>
#include <iostream>
using std::cout;
using std::endl;

//数学之中的复数, 负数怎么开方   -1 = i^2
class Complex
{
public:
	Complex(double dreal = 0, double dimage = 0)
	: _dreal(dreal)
	, _dimage(dimage)
	{	cout << "Complex(double,double)" << endl;}

	void print() const
	{
		cout << _dreal;
		if(_dimage > 0) {
			cout << " + " << _dimage << "i" << endl;
		} else if(_dimage == 0){
			return;
		} else {
			cout << " - " <<  _dimage * ( -1 )  << "i" << endl;
		}
	}

	//对于 += -= *= /=  %= 复合赋值运算符，
	//都建议以成员函数形式来进行重载
	//
	//当表达式执行完毕之后，其左操作数的值发生了变化
	Complex & operator+=(const Complex & rhs)
	{
		cout << "Complex & operator+=(const Complex&)" << endl;
		_dreal += rhs._dreal;
		_dimage += rhs._dimage;
		return *this;
	}

	//自增自减运算符
	//
	//由于前置形式和后置形式的操作数都只有一个，
	//在重载时，就无法区分前置和后置的形式了，
	//为了解决该问题，C++强制规定：后置形式再添加一个int参数
	Complex & operator++()
	{
		cout << "Complex & operator++()" << endl;
		++_dreal;
		++_dimage;
		return *this;
	}

	//后置形式
	//参数列表中的int只是为了与前置形式进行区分，
	//并不真正传递参数
	Complex operator++(int)
	{
		cout << "Complex operator++(int)" << endl;
		//先保存变化之前的值
		Complex tmp(*this);
		++_dreal;
		++_dimage;
		return tmp;
	}


	//假设以成员函数形式重载输出流运算符,
	//则左操作数是Complex对象，这与输出流运算符的
	//要求有矛盾, 因此输出流运算符不能以成员函数形式重载
#if 0
	std::ostream & operator<<(std::ostream & os)
	{
		os << _dreal << " + ";
		os << _dimage << "i";
		return os;
	}
#endif
	

	friend Complex operator+(const Complex & lhs, const Complex & rhs);
	friend bool operator>(const Complex & lhs, const Complex & rhs);
	friend std::ostream & operator<<(std::ostream & os, const Complex & rhs);
	friend std::istream & operator>>(std::istream & is, Complex & rhs);

private:
	double _dreal;
	double _dimage;
};

enum Priority
{
	CRIT = 0,
	ALERT = 1,
	ERROR = 2
};

//重载的类型必须是一个自定义类类型或枚举类型
//不能对内置类型的运算符进行重载, 编译报错
int operator+(Priority x, int y)
{	return x - y;}

//对于 + - * / % 双目运算符，倾向于使用友元函数形式进行重载
//以友元普通函数的形式重载, 返回值是一个对象
Complex operator+(const Complex & lhs, const Complex & rhs)
{
	cout << "Complex operator+(const Complex&,constComplex&)" << endl;
	return Complex(lhs._dreal + rhs._dreal,
				   lhs._dimage + rhs._dimage);
}

bool operator>(const Complex & lhs, const Complex & rhs)
{
	return lhs._dreal > rhs._dreal;
}

std::ostream & operator<<(std::ostream & os, const Complex & rhs)
{
	os << rhs._dreal;
	if(rhs._dimage > 0) {
		os << " + " << rhs._dimage << "i" << endl;
	} else if(rhs._dimage == 0){
		return os;
	} else {
		os << " - " <<  rhs._dimage * ( -1 )  << "i" << endl;
	}
	return os;
}

void readDouble(std::istream & is, double & number)
{
	cout << "pls input a valid double:" << endl;
	while(is >> number, !is.eof()) {
		if(is.bad()) {
			cout << "istream has broken!" << endl;
			return;
		} else if(is.fail()) {
			is.clear();
			is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			cout << "pls input a valid double:" << endl;
			continue;
		} else {
			break;
		}
	}
}

//需要考虑用户的异常操作
std::istream & operator>>(std::istream & is, Complex & rhs)
{
	/* is >> rhs._dreal >> rhs._dimage; */
	readDouble(is, rhs._dreal);
	readDouble(is, rhs._dimage);
	return is;
}
 
void test0() 
{
	int a = 1, b = 2;
	int c = a + b;

	a += b;//a的值发生了变化

	Complex c1(1, 2), c2(10, -3);
	Complex c3 = c1 + c2;
	cout << "c3:";
	c3.print();

	c1 += c2;
	cout << "\nc1:";
	c1.print();
} 

void test1()
{
	//表达式的值
	//a的值
	int a = 1;
	//前置形式
	//&(++a);//左值, 返回的就是a本身
	cout << "(++a):" << (++a) << endl;
	cout << "a:" << a << endl;
	//&(a++);//右值, 返回的是a变化之前的值
	cout << "(a++):" << a++ << endl;
	cout << "a:" << a << endl;
	
	Complex c1(1, 2);
	cout << "(++c1):";  
	(++c1).print();
	cout << "c1:";
	c1.print();

	cout << "(c1++):";
	(c1++).print();
	cout << "c1:";
	c1.print();
}

void test2()
{
	Complex c1(1, 2), c2(2, 3);
	cout << (c1 > c2) << endl;
}

void test3()
{
	int a = 1;
	cout << "a:" << a << endl;

	Complex c1(1, 2);
	//endl其实是一个函数名
	//
	//cout 执行一次输出流运算符之后，
	//返回的还是cout对象本身
	//
	//输出流运算符有左右两个操作数
	//其中左操作数是流对象，右操作数是内容
	cout << "c1:" << c1 << endl;
	/* cout << "c1:"; */
	/* c1 << cout; */

	//输入流运算符左操作数还是流对象
	std::cin >> c1;
	cout << "c1:" << c1 << endl;
}

















 
int main(void)
{
	/* test0(); */
	/* test1(); */
	/* test2(); */
	test3();
	return 0;
}
